今天要把前兩天的技術債補完,分別是System Instruction以及auipc/lui。
lui測試
設定imm為1,這樣讀進來的值會是0x1000
TEST(ISATESTSuite, LUI)
{
ALISS::reg[10] = 0x0;
uint32_t insn = 0x00001537; // lui,a0, 0x1
ALISS::ID_EX_WB(insn);
EXPECT_EQ(ALISS::reg[10], 0x1000 );
}
lui實作
程式碼相當簡單,取出rd以及imm之後做sext即可。
case 0x37: //lui
{
uint64_t rd = ((insn >> 7) & 0x1f);
uint64_t imm = ((insn >> 12) & 0xfffff);
reg[rd] = sext((imm << 12),32);
break;
}
auipc測試
設定imm為1,pc為0x1000這樣讀進來的值會是0x2000
TEST(ISATESTSuite, AUIPC)
{
ALISS::pc = 0x1000;
ALISS::reg[10] = 0x0;
uint32_t insn = 0x00001517; // auipc a0 0x1
ALISS::ID_EX_WB(insn);
EXPECT_EQ(ALISS::reg[10], 0x2000);
}
auipc實作
將lui程式碼再額外加上PC即可,要先sext imm之後再加。
case 0x17: //AUIPC
{
uint64_t rd = ((insn >> 7) & 0x1f);
uint64_t imm = ((insn >> 12) & 0xfffff);
reg[rd] = pc + sext((imm << 12),32);
break;
}
System Instruction測試
WFI和FENCE只要能正常執行,沒有Illegle instruction即可。
而ecall、ebreak及mret則比較麻煩,我們檢查ecall/ebreak/mret後的pc位置。
另外更正一下前面提到的內容有務的地方,就是ecall/ebreak等exception發生會根據mtvec設置為dircet mode或是vector mode,分別跳到mtvec base或者是base + cause * 4的位置,前面說會分別跳到處理ecall/ebreak的程式碼片段式vector mode才有的狀況,我們這邊會先當成dircet mode設置。
TEST(ISATESTSuite, EBREAK)
{
ALISS::csr[0x305] = 0x8000;
ALISS::pc = 0x1000;
uint32_t insn = 0x00100073; // ebreak;
ALISS::ID_EX_WB(insn);
EXPECT_EQ(ALISS::csr[0x341], 0x1000);
EXPECT_EQ(ALISS::next_pc, 0x8000); // jump to mtvec
}
TEST(ISATESTSuite, ECALL)
{
ALISS::csr[0x305] = 0x8000;
ALISS::pc = 0x1000;
uint32_t insn = 0x00000073; // ecall;
ALISS::ID_EX_WB(insn);
EXPECT_EQ(ALISS::csr[0x341], 0x1000); //epc = 0x1000
EXPECT_EQ(ALISS::next_pc, 0x8000); // jump to mtvec
}
TEST(ISATESTSuite, MRET)
{
ALISS::pc = 0x0;
ALISS::csr[0x341] = 0x1000;
uint32_t insn = 0x30200073; // mret
ALISS::ID_EX_WB(insn);
EXPECT_EQ(ALISS::next_pc, 0x1000); //ret to epc
}
System Instruction實作
ecall/ebrea的行為就是存下mepc,並跳到mtvec的位置,
mret的行為則是跳回mepc的位置。之後要把這些CSR位置設定成enum。
case 0: //System
{
uint64_t systemop = csrno;
switch(systemop)
{
case 0x0: //ecall
{
csr[0x341] = pc; //epc = pc
next_pc = csr[0x305]; //mtvec = 0x305
break;
}
case 0x1: //ebreak
{
csr[0x341] = pc;
next_pc = csr[0x305]; // mtvec = 0x305
break;
}
case 0x105: // wfi
{
//implement as nop ...
break;
}
case 0x302: //mret
{
next_pc = csr[0x341]; //epc = 0x341
break;
}
default:
{
printf("Illegal instruction");
printf("%x\n",insn);
break;
}
}
break;
}
碎碎念:明後兩天會把A/M-extension完成,之後就可以開始跑測試程式了,時程上可能來不及在30天內完成Linux開機,不過我會繼續到完成的那天orz